package util

import (
	"bytes"
	"encoding/json"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"strings"

	"github.com/astaxie/beego/logs"

	"cvevulner/common"
)

//RequestInfo http request information
type RequestInfo struct {
	URL           string
	Data          map[string]string //The data to be transmitted by the post, the key value must be both string
	DataInterface map[string]interface{}
}

//HTTPPatch patch request
func HTTPPatch(url string, requestBody string) (map[string]interface{}, error) {
	req, err := http.NewRequest("PATCH", url, bytes.NewBuffer([]byte(requestBody)))
	defer common.Catchs()
	if err != nil {
		return nil, err
	}
	urls := strings.Split(url, "access_token")
	if len(urls) > 0 {
		url = urls[0]
	}
	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		logs.Error("PATCH request failed, err: ", err, "body: ", requestBody, "url:", url)
		return nil, err
	}
	defer resp.Body.Close()

	status, _ := strconv.Atoi(resp.Status)
	if status > 300 {
		logs.Error("Patch request failed, err: ", err, "body: ", requestBody, "url:", url)
		return nil, err
	}
	body, err := ioutil.ReadAll(resp.Body)

	if err != nil || body == nil {
		logs.Error("PATCH failed, err: ", err, "body: ", requestBody)
		return nil, err
	}

	var iss map[string]interface{}
	err = json.Unmarshal(body, &iss)
	if err != nil {
		logs.Error(err, string(body))
		return nil, err
	}
	logs.Info(iss)
	return iss, nil
}

//HTTPPost post request
func HTTPPost(url string, requestBody string) (map[string]interface{}, error) {
	req, err := http.NewRequest("POST", url, bytes.NewBuffer([]byte(requestBody)))
	defer common.Catchs()
	if err != nil {
		return nil, err
	}
	urls := strings.Split(url, "access_token")
	if len(urls) > 0 {
		url = urls[0]
	}
	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		logs.Error("Post request failed, err: ", err, "body: ", requestBody, "url:", url)
		return nil, err
	}
	defer resp.Body.Close()

	status, _ := strconv.Atoi(resp.Status)
	if status > 300 {
		logs.Error("Post request failed, err: ", err, "body: ", requestBody, "url:", url)
		return nil, err
	}
	body, err := ioutil.ReadAll(resp.Body)

	if err != nil || body == nil {
		logs.Error("post failed, err: ", err, "body: ", requestBody)
		return nil, err
	}

	var iss map[string]interface{}
	err = json.Unmarshal(body, &iss)
	if err != nil {
		logs.Error(err, string(body))
		return nil, err
	}

	return iss, nil
}

//HTTPPost1 post request
func HTTPPost1(url string, requestBody string) ([]map[string]interface{}, error) {
	req, err := http.NewRequest("POST", url, bytes.NewBuffer([]byte(requestBody)))
	defer common.Catchs()
	if err != nil {
		return nil, err
	}
	urls := strings.Split(url, "access_token")
	if len(urls) > 0 {
		url = urls[0]
	}
	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		logs.Error("Post request failed, err: ", err, "body: ", requestBody, "url:", url)
		return nil, err
	}
	defer resp.Body.Close()

	status, _ := strconv.Atoi(resp.Status)
	if status > 300 {
		logs.Error("Post request failed, err: ", err, "body: ", requestBody, "url:", url)
		return nil, err
	}
	body, err := ioutil.ReadAll(resp.Body)

	if err != nil || body == nil {
		logs.Error("post failed, err: ", err, "body: ", requestBody)
		return nil, err
	}

	var iss []map[string]interface{}
	err = json.Unmarshal(body, &iss)
	if err != nil {
		logs.Error(err, string(body))
		return nil, err
	}

	return iss, nil
}

//PostURLEncoded request params encode
func PostURLEncoded(this RequestInfo) ([]byte, error) {
	client := &http.Client{}
	//post data to be submitted
	DataURLVal := url.Values{}
	for key, val := range this.Data {
		DataURLVal.Add(key, val)
	}
	req, err := http.NewRequest("POST", this.URL, strings.NewReader(DataURLVal.Encode()))
	if err != nil {
		logs.Error(err)
		return nil, err
	}
	//Camouflage head
	req.Header.Set("Accept", "application/json")
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")

	//Submit request
	resp, err := client.Do(req)
	if err != nil {
		logs.Error(err)
		return nil, err
	}
	defer resp.Body.Close()
	//Read return value
	result, err := ioutil.ReadAll(resp.Body)
	if err != nil || result == nil {
		logs.Error(err)
		return nil, err
	}
	logs.Info(string(result))
	return result, nil
}

//HTTPGet get request
func HTTPGet(url string) ([]map[string]interface{}, error) {
	resp, err := http.Get(url)
	urls := strings.Split(url, "access_token")
	if len(urls) > 0 {
		url = urls[0]
	}
	if err != nil {
		logs.Error("get error, url:", url, "error: ", err)
		return nil, err
	}

	defer resp.Body.Close()

	if resp.StatusCode >= 300 {
		logs.Error("resp.StatusCode:", resp.StatusCode, ",url: ", url)
		return nil, nil
	}

	body, err := io.ReadAll(resp.Body)
	if err != nil || body == nil {
		logs.Error("url:", url, ",err: ", err)
		return nil, err
	}

	var col []map[string]interface{}
	err = json.Unmarshal(body, &col)
	if err != nil {
		logs.Error("HTTPGet,err: ", err, "url: ", url)
	}

	return col, nil
}

//HTTPGetCom common get request
func HTTPGetCom(urls string) ([]byte, error) {
	resp, err := http.Get(urls)
	url := strings.Split(urls, "access_token")
	if len(url) > 0 {
		urls = url[0]
	}

	if err != nil {
		logs.Error("get error, url:", urls, "error: ", err)
		return nil, err
	}

	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil || body == nil {
		logs.Error(err)
		return nil, err
	}

	return body, nil
}

func HTTPGetDetail(url string) (map[string]interface{}, error) {
	resp, err := http.Get(url)
	urls := strings.Split(url, "access_token")
	if len(urls) > 0 {
		url = urls[0]
	}
	if err != nil {
		logs.Error("get error, url:", url, "error: ", err)
		return nil, err
	}

	defer resp.Body.Close()

	if resp.StatusCode >= 300 {
		logs.Error("resp.StatusCode:", resp.StatusCode, ",url: ", url)
		return nil, nil
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil || body == nil {
		logs.Error("url:", url, ",err: ", err)
		return nil, err
	}

	var col map[string]interface{}
	err = json.Unmarshal(body, &col)
	if err != nil {
		logs.Error("HTTPGet,err: ", err, "url: ", url)
	}

	return col, nil
}

func HTTPDelCom(url, requestBody string) ([]map[string]interface{}, error) {
	req, err := http.NewRequest("DELETE", url, bytes.NewBuffer([]byte(requestBody)))
	urls := strings.Split(url, "access_token")
	if len(urls) > 0 {
		url = urls[0]
	}
	defer common.Catchs()
	if err != nil {
		logs.Error("NewRequest, url: ", url, ",req: ", requestBody, ",err: ", err)
		return nil, err
	}
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		logs.Error("DELETE request failed, err: ", err, "body: ", requestBody, "url:", url)
		return nil, err
	}

	defer resp.Body.Close()

	status, _ := strconv.Atoi(resp.Status)
	if status > 300 {
		logs.Error("DELETE request failed, err: ", err, "body: ", requestBody, "url:", url)
		return nil, err
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil || body == nil {
		logs.Error("DELETE failed, err: ", err, "body: ", requestBody)
		return nil, err
	}

	var iss []map[string]interface{}
	err = json.Unmarshal(body, &iss)
	if err != nil {
		logs.Error(err, string(body))
		return nil, err
	}

	return iss, nil
}

//HTTPPut patch request
func HTTPPut(url string, requestBody string) ([]map[string]interface{}, error) {
	req, err := http.NewRequest("PUT", url, bytes.NewBuffer([]byte(requestBody)))
	urls := strings.Split(url, "access_token")
	if len(urls) > 0 {
		url = urls[0]
	}

	defer common.Catchs()

	if err != nil {
		return nil, err
	}

	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}

	resp, err := client.Do(req)
	if err != nil {
		logs.Error("PUT request failed, err: ", err, "body: ", requestBody, "url:", url)
		return nil, err
	}

	defer resp.Body.Close()

	status, _ := strconv.Atoi(resp.Status)
	if status > 300 {
		logs.Error("Patch request failed, err: ", err, "body: ", requestBody, "url:", url)
		return nil, err
	}
	body, err := ioutil.ReadAll(resp.Body)

	if err != nil || body == nil || len(body) == 0 {
		logs.Error("PUT failed, err: ", err, "body: ", requestBody)
		return nil, err
	}

	var iss []map[string]interface{}
	err = json.Unmarshal(body, &iss)
	if err != nil {
		logs.Error(err, string(body))
		return nil, err
	}

	return iss, nil
}

func HTTPPutMap(url string, requestBody string) (map[string]interface{}, error) {
	req, err := http.NewRequest("PUT", url, bytes.NewBuffer([]byte(requestBody)))
	urls := strings.Split(url, "access_token")
	if len(urls) > 0 {
		url = urls[0]
	}
	defer common.Catchs()

	if err != nil {
		return nil, err
	}

	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		logs.Error("PUT request failed, err: ", err, "body: ", requestBody, "url:", url)
		return nil, err
	}

	defer resp.Body.Close()

	status, _ := strconv.Atoi(resp.Status)
	if status > 300 {
		logs.Error("Patch request failed, err: ", err, "body: ", requestBody, "url:", url)
		return nil, err
	}
	body, err := ioutil.ReadAll(resp.Body)

	if err != nil || body == nil || len(body) == 0 {
		logs.Error("PUT failed, err: ", err, "body: ", requestBody)
		return nil, err
	}

	var iss map[string]interface{}
	err = json.Unmarshal(body, &iss)
	if err != nil {
		logs.Error(err, string(body))
		return nil, err
	}

	return iss, nil
}

func HTTPPostCom(req map[string]interface{}, url string) ([]byte, error) {
	bytesData, err := json.Marshal(req)
	if err != nil {
		logs.Error(err.Error())
		return bytesData, err
	}

	reader := bytes.NewReader(bytesData)
	request, err := http.NewRequest("POST", url, reader)
	urls := strings.Split(url, "access_token")
	if len(urls) > 0 {
		url = urls[0]
	}

	defer request.Body.Close()

	if err != nil {
		logs.Error(err.Error())
		return nil, err
	}

	request.Header.Set("Content-Type", "application/json;charset=UTF-8")
	client := http.Client{}
	resp, err := client.Do(request)
	if err != nil {
		logs.Error("url", url, ",req: ", req, ",err: ", err.Error())
		return nil, err
	}

	respBytes, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		logs.Error("url", url, ",req: ", req, ",err: ", err.Error())
		return respBytes, err
	}

	return respBytes, err
}
